Let’s make a GAME!!!!
本文将以Qt设计的一个飞机大战为例,讲解小游戏开发的一些基本要素。
基于Qt Scene的场景构建
场景、视窗和对象
QGraphicsScene
这个类就像一个场景类,你可以向场景类中添加各种各样的对象,例如放入一只猫或者一个英雄等等
QGraphicsView
这个类用于将场景进行可视化,如果不可视化场景,我们便看不到任何东西
QGraphicsItem
功能
这个类就是我们可以向场景中添加的对象,例如一个矩形(QGraphicsRectItem)
Item的组合
每个item可以有自己的parent,从而我们可以将多个item进行组合,这对于创造复杂的对象很有帮助,例如如果我们想创建一个坦克,坦克包含如下部分:
- 炮管
- 车身
我们可以令车身为炮管的parent,当parent被销毁时,child也会被销毁;而当chlid被销毁时,parent不会被销毁,这样我们可以实现如下的逻辑:当车身被打坏时,炮管连带也被销毁,而当炮管被打坏时,车身还在。
构建一个基本场景
综合代码
1 |
|
三者关系
三者关系可以用下图进行表示
graph TB subgraph QGraphicsScene subgraph QGraphicsView object1[QGraphicsRectItem] end end
视觉效果从上图可以看出,QGraphicsView其实就是可见区域,需要注意的是,当存在多个Item时,View默认是以多个Item的中心作为中心的,我们可以设置以某一个具体的Item作为中心或者以整个Scene作为中心。
坐标系系统
在Qt中,有三个坐标系系统需要我们注意:Scene、View和Item,左上角是三个坐标系的原点,通过改变其位置,我们能够得到不同的视觉效果。
对场景类的修改
尺寸修改
我们可以设置场景类的一些关键参数,从而实现理想的场景效果,例如在QGraphcsScene中,如果我们不限定其大小,随着场景中item越来越多,那么我们的Scene尺寸会越来越大,一般来说,我们会将Scene的尺寸和view的尺寸设置为一致。
1 | view->setFixedSize(800,600); |
对Item类的修改
添加item
1 | case Qt::Key_Space: //按下空格键 |
删除item
1 | if(pos().y() < 0 - this->rect().height()){ |
音频和图像
音频及图像Resources管理
一般来说,我们将多媒体素材放置在Qt的resourse中,右键项目,Add New,在Qt一栏中选择resource,即可添加,其后缀为.qrc。点击add prefix可以添加前缀,就是划分文件夹以便分类保管不同的资源。
声音
配置工程文件
为了添加声音,我们需要使用多媒体,修改项目工程文件,在Qt组件中添加多媒体
1 | QT += core gui \ |
添加背景音乐
1 | QMediaPlayer* bgm = new QMediaPlayer(); |
添加开火音效
在添加开火音效时,我们要注意音效的重复播放问题
1 | void Player::fireSound() |
图像
背景设置
1 | scene = new QGraphicsScene(); |
游戏角色设置
QGraphicsPixmapItem
为了使用具有图片属性的对象,我们需要使用QGraphicsPixmapItem类,该类能够为对象添加图元
创建一个具有图元属性的对象并进行处理
1 | /* |
人机交互事件
人机交互有多种事件,例如鼠标点击,键盘点击等等,本文将使用键盘触发相应事件
keyPressEvent() 和 QKeyEvent
我们定义好了一个对象叫MyRect,继承自QGraphicsRectItem,同时定义了keyPressEvent()函数如下
1 | void MyRect::keyPressEvent(QKeyEvent *event) |
现在我们按下键盘,发现并没有事情发生,因为在Qt中,同一时刻只能有一个focus的对象响应键盘事件,因此我们要将我们的MyRect对象设置为focus的。
1 | rect->setFlag(QGraphicsItem::ItemIsFocusable); //设置为可Focus的 |
event 传递系统
对于一个事件,我们要知道以下几点:
- 事件从何而来
- 事件到哪里去
- 事件何时触发
我们需要Qt中的event propogation system来控制事件的传递。具体原理如下
- QGraphicsView 监听键盘事件
- 当键盘事件来临后,QGraphicsView通知QGraphicsScene
- QGraphicsScene查看当前被Focus的QGraphicsItem,控制其动作
- QGraphicsItem检查并调用其keyPressEvent函数,完成动作
Timer
一些情况下我们需要触发定时器中断,此时我们需要设置Timer,例如在游戏中我们需要子弹自己运动,那么设置好定时器,然后将定时器与运动函数进行connect,从而实现子弹的自动移动
1 | Bullet::Bullet() |
游戏机制
碰撞检测
在子弹的飞行过程中,我们需要对子弹碰撞的物体进行检测,如果发现子弹碰撞到了飞机,那么立刻将子弹和飞机都销毁,
代码
1 | QList<QGraphicsItem*> colliding_item = collidingItems(); //获取碰撞的物体并保存在列表中 |